package view.trajectory;

import java.util.Iterator;

import graphics.engine.ProgramShader;

import javax.media.opengl.GL;

import colors.Color;

import mathematics.Matrix4x4;
import mathematics.geometry.Geometry;
import mathematics.geometry.PolylineGeometry;
import model.BaseModel;
import model.trajectory.BaseTrajectoryModel;
import settings.Settings;
import utils.Point3D;
import view.BaseView;

public abstract class BaseTrajectoryView extends BaseView
{
	public BaseTrajectoryView(BaseModel model) {
		super(model);
	}
	private BaseTrajectoryView lastSubtrajectory;
	private BaseTrajectoryView nextSubtrajectory;
	
	private PolylineGeometry geometry;
	
	public abstract void update(long time, long beginTime, long endTime);
	public abstract boolean mustDraw();
	
	public void Draw(GL gl, ProgramShader programShader, long logTime, long beginTime, long endTime)
	{
		//if(this.hasChanged())
		{
			this.update(logTime, beginTime, endTime);
			this.setHasChanged(false);
		}
		if( this.mustDraw() && this.geometry.size() != 0)
		{
			Matrix4x4 worldMatrix = new Matrix4x4();		
			worldMatrix.setToIdentity();
			gl.glUniformMatrix4fv(programShader.WorldMatrixUniformID, 1, false, worldMatrix.toFloatArray(), 0);		
		
			BaseTrajectoryModel model =  ((BaseTrajectoryModel)this.getModel());
			long beginGradiantTime = (long) (beginTime - Settings.TrajectoryGradiantLength);
			long endGradiantTime = (long) (endTime + Settings.TrajectoryGradiantLength);
			float alpha = 1.0f;
			if( model.parent.isHighlighted())
			{
				gl.glLineWidth(Settings.TrajectoryHighLightWidth);		
			}
			else
			{
				gl.glLineWidth(1.0f);		
			}
		
			long timeStep = ( model.intervalle.endTime -  model.intervalle.beginTime) / (long) this.getGeometry().size();
			long currentTime =  model.intervalle.beginTime;
			boolean isDashed = false;
			if( model.parent.isHighlighted() && Settings.AutoFadeTraj && model.intervalle.endTime > logTime )
			{
				gl.glLineStipple(1, (short) 0x00FF);  
				gl.glEnable(GL.GL_LINE_STIPPLE);
				isDashed = true;
					
			}
			gl.glBegin(GL.GL_LINE_STRIP);
			
			for(Iterator<Point3D> it = this.getGeometry().iterator(); it.hasNext(); )
			{
				Point3D point = it.next();
				currentTime = currentTime + timeStep;
	
				boolean displayBeginGradiant = (currentTime < beginTime) && (currentTime >= beginGradiantTime);
				//System.out.println("currentTime:" + currentTime + "beginTime:" + beginTime + "beginGradiantTime:" + beginGradiantTime );
				boolean displayEndGradiant = (currentTime > endTime) && (currentTime  <=  endGradiantTime);
				
				if((currentTime >= beginTime && currentTime <= endTime) || displayBeginGradiant || displayEndGradiant )
				{
		        	if (Settings.TrajectoryGradiant && displayBeginGradiant)
					{
						alpha = (1 / ((beginTime - currentTime) / (float)Settings.TrajectoryGradiantLength));	
					}
					
					if (Settings.TrajectoryGradiant && displayEndGradiant)
					{
						alpha = (1 / ((currentTime - endTime) / (float)Settings.TrajectoryGradiantLength));
					}
					if( !isDashed && Settings.AutoFadeTraj && currentTime > logTime )
					{
						gl.glEnd();
						gl.glLineStipple(1, (short) 0x00FF);  
						gl.glEnable(GL.GL_LINE_STIPPLE);

						gl.glBegin(GL.GL_LINE_STRIP);
						isDashed = true;
						
					}
					Color color =  model.parent.getColor();
					gl.glColor4f(color.R, color.G, color.B, alpha);
					gl.glVertex3d(point.x(), point.y(), point.z());
					
				}
			}
			gl.glEnd();
			gl.glDisable(GL.GL_LINE_STIPPLE);
		}
	}

	@Override
	public boolean hasChanged() {
		// TODO Auto-generated method stub
		return super.hasChanged();
	}
	
	public boolean isIntersectedByDisk(Geometry geometry) {
		return geometry.isIntersectedBy(this.getGeometry());
	}
	public BaseTrajectoryView getNextSubtrajectory() {
		return nextSubtrajectory;
	}
	public void setNextSubtrajectory(BaseTrajectoryView nextSubtrajectory) {
		this.nextSubtrajectory = nextSubtrajectory;
	}
	public BaseTrajectoryView getLastSubtrajectory() {
		return lastSubtrajectory;
	}
	public void setLastSubtrajectory(BaseTrajectoryView lastSubtrajectory) {
		this.lastSubtrajectory = lastSubtrajectory;
	}

	public PolylineGeometry getGeometry() {
		return geometry;
	}
	public void setGeometry(PolylineGeometry geometry) {
		this.geometry = geometry;
	}
}
